package com.startx.http.wordfilter;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 敏感词过滤器
 */
public class WordFilter {

    /**
     * 敏感词库
     */
    private final WordContext wordContext;
    private final Map sensitiveWordMap;
    private final ReentrantReadWriteLock lock;

    public WordFilter(WordContext wordContext) {
        this.wordContext = wordContext;
        this.sensitiveWordMap = this.wordContext.getSensitiveWordMap();
        this.lock = wordContext.getLock();
    }

    /**
     * 替换敏感词
     *
     * @param text     输入文本
     * @param distance 文本距离
     * @param symbol   替换符号
     */
    public String replace(final String text, final int distance, final char symbol) {
        char[] charest = text.toCharArray();
        for (int i = 0; i < charest.length; i++) {
            FlagIndex fi = getFlagIndex(charest, i, distance);
            if (fi.isFlag()) {
                for (int j : fi.getIndex()) {
                    charest[j] = symbol;
                }
            }
        }
        return new String(charest);
    }

    /**
     * 是否包含敏感词
     *
     * @param text     输入文本
     * @param distence 文本距离
     */
    public boolean include(final String text, final int distance) {
        boolean flag = false;
        char[] charest = text.toCharArray();
        for (int i = 0; i < charest.length; i++) {
            flag = getFlagIndex(charest, i, distance).isFlag();
            if (flag) {
                break;
            }
        }
        return flag;
    }

    /**
     * 获取敏感词数量
     *
     * @param text     输入文本
     * @param distance 文本距离
     */
    public int wordcount(final String text, final int distance) {
        int count = 0;
        char[] charest = text.toCharArray();
        for (int i = 0; i < charest.length; i++) {
            FlagIndex fi = getFlagIndex(charest, i, distance);
            if (fi.isFlag()) {
                count++;
            }
        }
        return count;
    }

    /**
     * 获取敏感词列表
     *
     * @param text     输入文本
     * @param distance 文本距离
     */
    public List<String> wordlist(final String text, final int distance) {
        List<String> sensitives = new ArrayList<>();
        char[] charest = text.toCharArray();
        for (int i = 0; i < charest.length; i++) {
            FlagIndex fi = getFlagIndex(charest, i, distance);
            if (fi.isFlag()) {
                StringBuilder sb = new StringBuilder();
                for (int j : fi.getIndex()) {
                    char word = text.charAt(j);
                    sb.append(word);
                }
                sensitives.add(sb.toString());
            }
        }
        return sensitives;
    }

    /**
     * 获取标记索引
     *
     * @param charest  输入文本
     * @param begin    检测起始
     * @param distance 文本距离
     */
    private FlagIndex getFlagIndex(final char[] charest, final int begin, final int distance) {
        try {
            lock.readLock().lock();
            FlagIndex fi = new FlagIndex();

            Map nowMap = sensitiveWordMap;
            boolean flag = false;
            int count = 0;
            List<Integer> index = new ArrayList<>();
            for (int i = begin; i < charest.length; i++) {
                char word = charest[i];
                Map mapTree = (Map) nowMap.get(word);
                if (count > distance || (i == begin && Objects.isNull(mapTree))) {
                    break;
                }
                if (!Objects.isNull(mapTree)) {
                    nowMap = mapTree;
                    count = 0;
                    index.add(i);
                } else {
                    count++;
                }
                if ("1".equals(nowMap.get("isEnd"))) {
                    flag = true;
                    break;
                }
            }

            fi.setFlag(flag);
            fi.setIndex(index);

            return fi;
        } finally {
            lock.readLock().unlock();
        }
    }
}
